import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

class FileChannelUtil {
  /// 自己的 ID
  final String sender;

  /// 对方 ID
  final String receiver;

  /// WebSocket 信令通道，用于交换 SDP 和 ICE 候选
  final WebSocketChannel mWebSocketClient;

  /// WebRTC 连接对象
  RTCPeerConnection? _peerConnection;

  /// WebRTC 数据通道，用于传输实际的聊天数据
  RTCDataChannel? _dataChannel;

  /// 收到消息时的回调函数
  final void Function(String) onMessage;

  /// 收到文件时的回调函数
  final void Function(Uint8List, String)? onFileReceived;

  /// 构造函数
  FileChannelUtil({
    required this.sender,
    required this.receiver,
    required this.mWebSocketClient,
    required this.onMessage,
    this.onFileReceived,
  });

  /// 创建 Offer（发起方调用）
  /// 初始化 WebRTC 连接并创建 Offer 发送给对端
  Future<void> createOffer() async {
    // 配置 ICE 服务器，使用 Google 的 STUN 服务器
    final config = <String, dynamic>{
      'iceServers': [
        {'urls': 'stun:stun.qq.com:3478'},
      ],
    };

    // 创建 WebRTC 近端连接
    _peerConnection = await createPeerConnection(config);

    // 配置 DataChannel 参数
    final dataChannelInit = RTCDataChannelInit()
      ..negotiated = false // 不使用应用层协商
      ..ordered = true // 保证消息顺序
      ..maxRetransmits = 5; // 最大重传次数

    // 创建数据通道
    _dataChannel = await _peerConnection!.createDataChannel('file', dataChannelInit);

    // 设置数据通道监听器
    _setupDataChannel();

    // 监听 ICE 候选地址，发现后通过信令服务器发送给对端
    _peerConnection!.onIceCandidate = (candidate) {
      if (candidate == null) return;
      _sendSignal('candidate', {
        'candidate': candidate.candidate,
        'sdpMid': candidate.sdpMid,
        'sdpMLineIndex': candidate.sdpMLineIndex
      });
    };

    // 创建并发送 Offer
    final offer = await _peerConnection!.createOffer();
    await _peerConnection!.setLocalDescription(offer);
    // 通过信令服务器发送 Offer 给对端
    _sendSignal('offer', {'sdp': offer.sdp, 'type': offer.type});
  }

  /// 处理收到的 Offer（接收方调用）
  /// 接收 Offer 并回复 Answer
  Future<void> handleOffer(Map<String, dynamic> data) async {
    final sdp = data['sdp'];
    final type = data['type'];
    // 配置 ICE 服务器
    final config = <String, dynamic>{
      'iceServers': [
        {'urls': 'stun:stun.qq.com:3478'},
      ],
    };

    // 创建 WebRTC 近端连接
    _peerConnection = await createPeerConnection(config);

    // 监听对端创建的数据通道
    _peerConnection!.onDataChannel = (channel) {
      _dataChannel = channel;
      _setupDataChannel(); // 设置消息监听
    };

    // 监听 ICE 候选地址
    _peerConnection!.onIceCandidate = (candidate) {
      if (candidate == null) return;
      _sendSignal('candidate', {
        'candidate': candidate.candidate,
        'sdpMid': candidate.sdpMid,
        'sdpMLineIndex': candidate.sdpMLineIndex
      });
    };

    // 设置远端描述（收到的 Offer）
    await _peerConnection!.setRemoteDescription(RTCSessionDescription(sdp, type));

    // 创建并发送 Answer
    final answer = await _peerConnection!.createAnswer();
    await _peerConnection!.setLocalDescription(answer);

    _sendSignal('answer', {'sdp': answer.sdp, 'type': answer.type});
  }

  /// 处理收到的 Answer（发起方调用）
  /// 设置远端描述
  Future<void> handleAnswer(Map<String, dynamic> data) async {
    final sdp = data['sdp'];
    final type = data['type'];
    await _peerConnection!.setRemoteDescription(RTCSessionDescription(sdp, type));
  }

  /// 处理收到的 ICE 候选地址
  /// 添加候选地址以建立网络连接
  Future<void> handleCandidate(Map<String, dynamic> data) async {
    final candidate = RTCIceCandidate(
        data['candidate'], data['sdpMid'], data['sdpMLineIndex']);
    await _peerConnection!.addCandidate(candidate);
  }

  /// 设置 DataChannel 消息监听
  /// 配置消息接收和状态变化处理
  void _setupDataChannel() {
    // 监听接收到的消息
    _dataChannel!.onMessage = (RTCDataChannelMessage message) {
      if (message.isBinary) {
        // 处理二进制数据（文件）
        print('收到二进制数据：${message.binary.length} 字节');
        // 触发收到文件的回调
        onFileReceived?.call(message.binary, 'received_file.dat');
      } else {
        // 处理控制消息
        try {
          final Map<String, dynamic> controlMsg = json.decode(message.text);
          if (controlMsg['type'] == 'file_info') {
            // 文件信息消息
            final fileName = controlMsg['fileName'];
            final fileSize = controlMsg['fileSize'];
            onMessage('准备接收文件: $fileName ($fileSize 字节)');
          } else {
            // 其他文本消息
            onMessage(message.text);
          }
        } catch (e) {
          // 如果不是JSON格式，则作为普通文本消息处理
          onMessage(message.text);
        }
      }
    };

    // 监听 DataChannel 状态变化
    _dataChannel!.onDataChannelState = (RTCDataChannelState state) {
      if (state == RTCDataChannelState.RTCDataChannelOpen) {
        print('DataChannel 已打开，可以传输文件');
        onMessage('DataChannel 已打开，可以传输文件');
      } else if (state == RTCDataChannelState.RTCDataChannelClosed) {
        print('DataChannel 已关闭');
        onMessage('DataChannel 已关闭');
      } else if (state == RTCDataChannelState.RTCDataChannelClosing) {
        print('DataChannel 正在关闭');
        onMessage('DataChannel 正在关闭');
      } else if (state == RTCDataChannelState.RTCDataChannelConnecting) {
        print('DataChannel 正在连接');
        onMessage('DataChannel 正在连接');
      }
    };
  }

  /// 发送文本消息
  /// [text] 要发送的文本内容
  void sendMessage(String text) {
    // 检查数据通道是否已打开
    if (_dataChannel != null &&
        _dataChannel!.state == RTCDataChannelState.RTCDataChannelOpen) {
      print('发送消息：$text');
      _dataChannel!.send(RTCDataChannelMessage(text));
    } else {
      print('DataChannel 未就绪');
      onMessage('DataChannel 未就绪');
    }
  }

  /// 发送文件
  /// [fileBytes] 文件字节数据
  /// [fileName] 文件名
  void sendFile(Uint8List fileBytes, String fileName) {
    // 检查数据通道是否已打开
    if (_dataChannel != null &&
        _dataChannel!.state == RTCDataChannelState.RTCDataChannelOpen) {
      // 先发送文件信息
      final fileInfoMsg = json.encode({
        'type': 'file_info',
        'fileName': fileName,
        'fileSize': fileBytes.length,
      });
      
      _dataChannel!.send(RTCDataChannelMessage(fileInfoMsg));
      
      // 发送文件数据
      _dataChannel!.send(RTCDataChannelMessage.fromBinary(fileBytes));
      
      onMessage('文件发送完成: $fileName (${fileBytes.length} 字节)');
    } else {
      print('DataChannel 未就绪');
      onMessage('DataChannel 未就绪，无法发送文件');
    }
  }

  /// 发送信令消息
  /// 通过 WebSocket 信令通道发送 SDP 或 ICE 候选
  /// [type] 消息类型（offer/answer/candidate）
  /// [data] 消息数据
  void _sendSignal(String type, Map<String, dynamic> data) {
    //发送消息到服务器
    mWebSocketClient.sink.add(
      jsonEncode({
        'type': type,
        'sender': sender,
        'receiver': receiver,
        'data': {...data, 'receiver': receiver},
      }),
    );
  }

  /// 从服务器接收消息
  /// 获取信令消息流
  /// 返回解析后的信令消息流
  Stream<Map<String, dynamic>> get signalStream =>
      mWebSocketClient.stream.map((msg) => jsonDecode(msg));

  /// 释放资源
  /// 关闭数据通道、连接和信令通道
  void dispose() {
    _dataChannel?.close();
    _peerConnection?.close();
    mWebSocketClient.sink.close();
  }
}